package org.dxy.domain.model.aggregate.impl;

import lombok.Builder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.dxy.domain.command.equipment.ReassignTaskDueToFailureCommand;
import org.dxy.domain.command.workorder.*;
import org.dxy.domain.event.DomainEvent;
import org.dxy.domain.event.workorder.*;
import org.dxy.domain.model.aggregate.Equipment;
import org.dxy.domain.model.aggregate.WorkOrder;
import org.dxy.domain.model.valobj.WorkOrderId;
import org.dxy.domain.model.valobj.WorkOrderStatusEnum;

import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import java.util.Objects;

/**
 * @description: 工单聚合根实现类
 * @author: dxy 
 * @createTime: 2025/6/22 17:26 
 */
@Slf4j
@Getter
@Builder
public class WorkOrderAggRoot implements WorkOrder {
    /** 工单ID */
    private WorkOrderId workOrderId;
    /** 工单编码 */
    private String workOrderCode;
    /** 产品型号 */
    private Long productId;
    /** 工艺路线编码 */
    private Long routeId;
    /** 产线编码 */
    private Long productionLineId;
    /** 计划数量 */
    private Integer plannedQuantity;
    /** 工单状态 */
    private WorkOrderStatusEnum status;

    // === 事件集合 ===
    private final List<DomainEvent> domainEvents = new ArrayList<>();

    // === 事件相关方法 ===
    @Override
    public List<DomainEvent> getDomainEvents() {
        return Collections.unmodifiableList(domainEvents);
    }

    @Override
    public void addDomainEvent(DomainEvent event) {
        domainEvents.add(event);
    }

    @Override
    public void clearDomainEvents() {
        domainEvents.clear();
    }

    @Override
    public boolean hasDomainEvents() {
        return !domainEvents.isEmpty();
    }

    @Override
    public boolean hasNoDomainEvents() {
        return domainEvents.isEmpty();
    }

    // === 业务方法 ===
    public static WorkOrder create(Long workOrderId, CreateWorkOrderCommand command) {
        // 1. 校验工单编码不能为空
        if (command.workOrderCode() == null || command.workOrderCode().trim().isEmpty()) {
            throw new IllegalArgumentException("工单编码不能为空");
        }

        // 2. 校验产品ID必须大于0
        if (command.productId() <= 0) {
            throw new IllegalArgumentException("产品ID必须大于0");
        }

        // 3. 校验计划数量必须大于0
        if (command.plannedQuantity() <= 0) {
            throw new IllegalArgumentException("计划数量必须大于0");
        }

        // 4. 校验工艺路线ID（可选，如果提供则必须大于0）
        if (command.routeId() != null && command.routeId() <= 0) {
            throw new IllegalArgumentException("工艺路线ID必须大于0");
        }

        // 5. 校验产线ID（可选，如果提供则必须大于0）
        if (command.productionLineId() != null && command.productionLineId() <= 0) {
            throw new IllegalArgumentException("产线ID必须大于0");
        }

        WorkOrderAggRoot workOrder = WorkOrderAggRoot.builder()
                .workOrderId(WorkOrderId.of(workOrderId))
                .workOrderCode(command.workOrderCode())
                .productId(command.productId())
                .plannedQuantity(command.plannedQuantity())
                .routeId(command.routeId())
                .productionLineId(command.productionLineId())
                .status(WorkOrderStatusEnum.READY) // 直接设为准备完成状态
                .build();

        // 发布工单创建事件
        workOrder.addDomainEvent(new WorkOrderCreatedEvent(
                workOrder.getWorkOrderId().getValue(),
                workOrder.getWorkOrderCode(),
                workOrder.getProductId(),
                workOrder.getStatus().getKey()
        ));

        // 如果指定了工艺路线，发布路线分配事件
        if (command.routeId() != null) {
            workOrder.addDomainEvent(new RouteAssignedToOrderEvent(
                    workOrder.getWorkOrderId().getValue(),
                    workOrder.getWorkOrderCode(),
                    command.routeId()
            ));
        }

        // 如果指定了产线，发布产线分配事件
        if (command.productionLineId() != null) {
            workOrder.addDomainEvent(new LineAssignedToOrderEvent(
                    workOrder.getWorkOrderId().getValue(),
                    workOrder.getWorkOrderCode(),
                    command.productionLineId()
            ));
        }

        return workOrder;
    }



    @Override
    public void release(ReleaseWorkOrderCommand command) {
        if (status != WorkOrderStatusEnum.CREATED) {
            throw new IllegalStateException("只有已创建状态的工单才能下达");
        }
        
        this.status = WorkOrderStatusEnum.RELEASED;
        addDomainEvent(new WorkOrderReleasedEvent(
                workOrderId.getValue(),
                workOrderCode,
                productId,
                this.status.getKey()
        ));
    }

    @Override
    public void start(StartWorkOrderCommand command) {
        if (status != WorkOrderStatusEnum.RELEASED) {
            throw new IllegalStateException("只有已下达状态的工单才能开始生产");
        }
        
        this.status = WorkOrderStatusEnum.STARTED;
        addDomainEvent(new WorkOrderStartedEvent(
                workOrderId.getValue(),
                workOrderCode,
                productId,
                this.status.getKey()
        ));
    }

    @Override
    public void suspend(org.dxy.domain.command.workorder.SuspendWorkOrderCommand command) {
        if (status != WorkOrderStatusEnum.STARTED) {
            throw new IllegalStateException("只有生产中的工单才能暂停");
        }
        
        this.status = WorkOrderStatusEnum.SUSPENDED;
        addDomainEvent(new WorkOrderSuspendedEvent(
                workOrderId.getValue(),
                workOrderCode,
                productId,
                this.status.getKey()
        ));
    }

    @Override
    public void resume(ResumeWorkOrderCommand command) {
        if (status != WorkOrderStatusEnum.SUSPENDED) {
            throw new IllegalStateException("只有暂停状态的工单才能恢复");
        }
        
        this.status = WorkOrderStatusEnum.STARTED;
        addDomainEvent(new WorkOrderResumedEvent(
                workOrderId.getValue(),
                workOrderCode,
                productId,
                this.status.getKey()
        ));
    }

    @Override
    public void complete(CompleteWorkOrderCommand command) {
        if (status != WorkOrderStatusEnum.STARTED) {
            throw new IllegalStateException("只有生产中的工单才能完成");
        }
        
        this.status = WorkOrderStatusEnum.COMPLETED;
        addDomainEvent(new WorkOrderCompletedEvent(
                workOrderId.getValue(),
                workOrderCode,
                productId,
                command.completedQuantity(),
                this.status.getKey()
        ));
    }

    @Override
    public void close(CloseWorkOrderCommand command) {
        if (status != WorkOrderStatusEnum.COMPLETED) {
            throw new IllegalStateException("只有已完成的工单才能关闭");
        }
        
        this.status = WorkOrderStatusEnum.CLOSED;
        addDomainEvent(new WorkOrderClosedEvent(
                workOrderId.getValue(),
                workOrderCode,
                productId,
                "工单正常关闭", // 默认关闭原因，实际应该从请求中获取
                this.status.getKey()
        ));
    }

    @Override
    public void cancel(CancelWorkOrderCommand command) {
        if (status == WorkOrderStatusEnum.COMPLETED || status == WorkOrderStatusEnum.CLOSED) {
            throw new IllegalStateException("已完成或已关闭的工单不能取消");
        }
        
        this.status = WorkOrderStatusEnum.CANCELLED;
        addDomainEvent(new WorkOrderCancelledEvent(
                workOrderId.getValue(),
                workOrderCode,
                productId,
                "工单取消", // 默认取消原因，实际应该从请求中获取
                this.status.getKey()
        ));
    }

    @Override
    public void reassignTaskDueToFailure(ReassignTaskDueToFailureCommand command, Equipment original, Equipment target) {
        // 设备故障任务重分配逻辑
    }

    /**
     * 修改计划数量
     */
    public void changeQuantity(Integer newQuantity) {
        if (newQuantity != null && newQuantity <= 0) {
            throw new IllegalArgumentException("计划数量必须大于0");
        }
        
        if (!Objects.equals(this.plannedQuantity, newQuantity)) {
            this.plannedQuantity = newQuantity;
            addDomainEvent(new WorkOrderQuantityChangedEvent(
                    workOrderId.getValue(),
                    workOrderCode,
                    newQuantity
            ));
        }
    }

    /**
     * 分配产线
     */
    public void changeProductionLine(Long lineId) {
        if (!Objects.equals(this.productionLineId, lineId)) {
            this.productionLineId = lineId;
            addDomainEvent(new WorkOrderLineChangedEvent(
                    workOrderId.getValue(),
                    workOrderCode,
                    lineId
            ));
        }
    }

    /**
     * 更换工艺路线
     */
    public void changeRoute(Long newRouteId) {
        if (!Objects.equals(this.routeId, newRouteId)) {
            this.routeId = newRouteId;
            addDomainEvent(new WorkOrderRouteChangedEvent(
                    workOrderId.getValue(),
                    workOrderCode,
                    newRouteId
            ));
        }
    }

    /**
     * 批量更新（保留原有方法以兼容现有代码）
     * @deprecated 建议使用更细粒度的更新方法
     */
    @Deprecated
    @Override
    public void update(UpdateWorkOrderCommand command) {
        Integer plannedQuantity = command.plannedQuantity();
        // 校验计划数量必须大于0
        if (plannedQuantity != null && plannedQuantity <= 0) {
            throw new IllegalArgumentException("计划数量必须大于0");
        }

        // 更新工单信息
        this.workOrderCode = command.workOrderCode();
        this.productId = command.productId();
        this.plannedQuantity = plannedQuantity;
        this.routeId = command.routeId();
        this.productionLineId = command.productionLineId();

        // 发布工单更新事件
        addDomainEvent(new WorkOrderUpdatedEvent(
                workOrderId.getValue(),
                workOrderCode,
                productId,
                plannedQuantity,
                routeId,
                productionLineId,
                this.status.getKey()
        ));
    }

    @Override
    public void delete() {
        // 发布工单删除事件
        addDomainEvent(new WorkOrderDeletedEvent(
                workOrderId.getValue(),
                workOrderCode,
                productId,
                this.status.getKey()
        ));
    }

    @Override
    public boolean canUpdate() {
        // 只有已创建和已下达状态的工单可以更新
        return status == WorkOrderStatusEnum.CREATED || status == WorkOrderStatusEnum.RELEASED;
    }

    @Override
    public boolean canDelete() {
        // 只有已创建、已取消、已关闭状态的工单可以删除
        return status == WorkOrderStatusEnum.CREATED ||
               status == WorkOrderStatusEnum.CANCELLED ||
               status == WorkOrderStatusEnum.CLOSED;
    }

    // === 事件应用方法 ===
    /**
     * 应用工单创建事件
     */
    public void applyCreatedEvent(WorkOrderCreatedEvent event) {
        this.workOrderCode = event.workOrderCode();
        this.productId = event.productId();
        this.status = WorkOrderStatusEnum.CREATED;
    }

    /**
     * 应用工单更新事件
     */
    public void applyUpdatedEvent(WorkOrderUpdatedEvent event) {
        this.workOrderCode = event.workOrderCode();
        this.productId = event.productId();
        this.plannedQuantity = event.plannedQuantity();
        this.routeId = event.routeId();
        this.productionLineId = event.productionLineId();
    }

    /**
     * 应用工单下达事件
     */
    public void applyReleasedEvent(WorkOrderReleasedEvent event) {
        this.status = WorkOrderStatusEnum.RELEASED;
    }

    /**
     * 应用工单开始事件
     */
    public void applyStartedEvent(WorkOrderStartedEvent event) {
        this.status = WorkOrderStatusEnum.STARTED;
    }

    /**
     * 应用工单暂停事件
     */
    public void applySuspendedEvent(WorkOrderSuspendedEvent event) {
        this.status = WorkOrderStatusEnum.SUSPENDED;
    }

    /**
     * 应用工单恢复事件
     */
    public void applyResumedEvent(WorkOrderResumedEvent event) {
        this.status = WorkOrderStatusEnum.STARTED;
    }

    /**
     * 应用工单完成事件
     */
    public void applyCompletedEvent(WorkOrderCompletedEvent event) {
        this.status = WorkOrderStatusEnum.COMPLETED;
    }

    /**
     * 应用工单关闭事件
     */
    public void applyClosedEvent(WorkOrderClosedEvent event) {
        this.status = WorkOrderStatusEnum.CLOSED;
    }

    /**
     * 应用工单取消事件
     */
    public void applyCancelledEvent(WorkOrderCancelledEvent event) {
        this.status = WorkOrderStatusEnum.CANCELLED;
    }

    /**
     * 应用工单删除事件
     */
    public void applyDeletedEvent(WorkOrderDeletedEvent event) {
        // 删除事件通常不会改变聚合状态，因为聚合已被删除
        log.warn("工单ID {} 的工单已被删除，尝试回放删除事件。", event.workOrderId());
    }
}
